import types
import sys
import os
from django.db.models.fields import *

from django.db.models import *
#from django.db.exceptions import *
from django.db.models.base import ModelBase, Model
from mongomodel.fields import *


def manager_get( org_func, *args, **kwargs):
    try :
        return org_func( *args, **kwargs )
    except org_func.im_self.model.DoesNotExist:
        return None

def manager_raw( org_func, *args, **kwargs):
    from mongomodel.mongodb.query import MongoRawQuerySet

    self = org_func.im_self

    return MongoRawQuerySet( self.model, self.db,*args, **kwargs )
    #return org_func( *args, **kwargs )

class MongoModelBase(ModelBase):

    def __new__(cls, name, bases, attrs):
        new_cls = super(MongoModelBase, cls).__new__(cls, name, bases, attrs )
        cls.override_raw( new_cls )
        return new_cls

    def use_object_name_for_table_name(cls, new_cls):
        new_cls._meta.db_table = new_cls._meta.object_name

    def return_null_for_not_exist(cls, new_cls):
        if hasattr(new_cls, '_default_manager'):
            org_func = new_cls._default_manager.get 
            new_cls._default_manager.get = lambda *args,**kwargs: manager_get( org_func, *args, **kwargs)

    def override_raw( new_cls):
        if hasattr(new_cls, '_default_manager'):
            org_func = new_cls._default_manager.raw 
            new_cls._default_manager.raw = lambda *args,**kwargs: manager_raw( org_func, *args, **kwargs)

class MongoModel(Model):

    __metaclass__ = MongoModelBase
    _id = MongoAutoField(verbose_name='_id', primary_key=True,
            auto_created=True)

    class Meta:
        abstract = True

    def as_dict(self, traverse=False):

        d = {}
        for f in self._meta.local_fields:
            if isinstance(f, AutoField) : 
                name = f.name
            else:
                name = f.attname
            value = getattr(self, name )
            if traverse:
                if hasattr( value ,'as_dict' ):
                    value = value.as_dict()
                elif isinstance( value, list ):
                    value = [ getattr(v,'as_dict',lambda:v)() for v in value]
            d[ name ] = value
        return d

    @classmethod
    def create_indexes(cls):
        choice = cls._meta.filter( key = key)
        if choice:
            return choice[0].data.items()
        else:
            return ()



class EmbeddedModel(MongoModel):

    #_embedded_fk = ForeignKey(EmbeddedParent)

    class Meta:
        abstract = True

    def as_dict(self, traverse=False):
        d = super(EmbeddedModel, self ).as_dict(traverse)
        d.pop( self._meta.pk.name )

        return d

    def save(self):
        raise Exception("Do Not call save on EmbeddedModel")

    def prepare_database_save(self, field):
        return field.get_db_prep_save(self)


class ConstantsModel(MongoModel):

    key = CharField(max_length=500, unique=True)
    data = DictField()
    description = CharField(max_length=500, null=True)

    class Meta:
        abstract = True

    def get_value(self):
        return self.data['_']

    def set_value(self, v):
        self.data = {'_': v}

    value = property(get_value, set_value)

    @classmethod
    def choices(cls, key):
        choice = cls.objects.filter( key = key)
        if choice :
            return choice[0].data and choice[0].data.items() or ()
        else:
            return ()
        
